/**
 * @copyright 2015 Indie Semiconductor.
 *
 * This file is proprietary to Indie Semiconductor.
 * All rights reserved. Reproduction or distribution, in whole
 * or in part, is forbidden except by express written permission
 * of Indie Semiconductor.
 *
 * @file gpio_sfrs.c
 */

#include <stdbool.h>
#include "orion.h"
#include "gpio_sfr_access.h"

void GPIOA_EnablePullUp(uint8_t pos, bool bit)
{
    switch(pos) {
    case 0:
        IOCTRLA_SFRS->GPAP03.PUENA0 = bit;
        break;
    case 1:
        IOCTRLA_SFRS->GPAP03.PUENA1 = bit;
        break;
    case 2:
        IOCTRLA_SFRS->GPAP03.PUENA2 = bit;
        break;
    case 3:
        IOCTRLA_SFRS->GPAP03.PUENA3 = bit;
        break;
    case 4:
        IOCTRLA_SFRS->GPAP4.PUENA4 = bit;
        break;
    default:
        break;
    }
}

void GPIOA_EnablePullDown(uint8_t pos, bool bit)
{
    switch(pos) {
    case 0:
        IOCTRLA_SFRS->GPAP03.PDENA0 = bit;
        break;
    case 1:
        IOCTRLA_SFRS->GPAP03.PDENA1 = bit;
        break;
    case 2:
        IOCTRLA_SFRS->GPAP03.PDENA2 = bit;
        break;
    case 3:
        IOCTRLA_SFRS->GPAP03.PDENA3 = bit;
        break;
    case 4:
        IOCTRLA_SFRS->GPAP4.PDENA4 = bit;
        break;
    default:
        break;
    }
}

void GPIOA_EnableOutput(uint8_t pos, bool bit)
{
    switch (pos) {
    case 0:
       GPIOA_SFRS->GPAP03.DIR0 = bit;
       break;
    case 1:
       GPIOA_SFRS->GPAP03.DIR1 = bit;
       break;
    case 2:
       GPIOA_SFRS->GPAP03.DIR2 = bit;
       break;
    case 3:
       GPIOA_SFRS->GPAP03.DIR3 = bit;
       break;
    case 4:
       GPIOA_SFRS->GPAP4.DIR4 = bit;
       break;
    default:
        break;
    }
}

void GPIOA_EnableInput(uint8_t pos, bool bit)
{
    switch(pos) {
    case 0:
        if (bit) {
            IOCTRLA_SFRS->GPAP03.RDENA0 = 1;
            GPIOA_SFRS->GPAP03.DIR0 = 0;
        } else {
            IOCTRLA_SFRS->GPAP03.RDENA0 = 1;
            GPIOA_SFRS->GPAP03.DIR0 = 1;
        }
        break;
    case 1:
        if (bit) {
            IOCTRLA_SFRS->GPAP03.RDENA1 = 1;
            GPIOA_SFRS->GPAP03.DIR1 = 0;
        } else {
            IOCTRLA_SFRS->GPAP03.RDENA1 = 1;
            GPIOA_SFRS->GPAP03.DIR1 = 1;
        }
        break;
    case 2:
        if (bit) {
            IOCTRLA_SFRS->GPAP03.RDENA2 = 1;
            GPIOA_SFRS->GPAP03.DIR2 = 0;
        } else {
            IOCTRLA_SFRS->GPAP03.RDENA2 = 1;
            GPIOA_SFRS->GPAP03.DIR2 = 0;
        }
        break;
    case 3:
        if (bit) {
            IOCTRLA_SFRS->GPAP03.RDENA3 = 1;
            GPIOA_SFRS->GPAP03.DIR3 = 0;
        } else {
            IOCTRLA_SFRS->GPAP03.RDENA3 = 1;
            GPIOA_SFRS->GPAP03.DIR3 = 0;
        }
        break;
    case 4:
        if (bit) {
            IOCTRLA_SFRS->GPAP4.RDENA4 = 1;
            GPIOA_SFRS->GPAP4.DIR4 = 0;
        } else {
            IOCTRLA_SFRS->GPAP4.RDENA4 = 1;
            GPIOA_SFRS->GPAP4.DIR4 = 0;
        }
        break;
    default:
        break;
    }
}

void GPIOA_SelectMode(uint8_t pos, uint8_t mode)
{
    switch(pos) {
    case 0:
        IOCTRLA_SFRS->GPAP03.HWMODE0 = mode;
        break;
    case 1:
        IOCTRLA_SFRS->GPAP03.HWMODE1 = mode;
        break;
    case 2:
        IOCTRLA_SFRS->GPAP03.HWMODE2 = mode;
        break;
    case 3:
        IOCTRLA_SFRS->GPAP03.HWMODE3 = mode;
        break;
    default:
        break;
    }
}

void GPIOA_EnableInterrupt(uint8_t pos, bool r, bool f)
{
    switch (pos) {
    case 0:
        if (r)
            GPIOA_SFRS->GPAP03.RE0 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE0 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE0 = 1;
        else
            GPIOA_SFRS->GPAP03.IE0 = 0;
        break;
    case 1:
        if (r)
            GPIOA_SFRS->GPAP03.RE1 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE1 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE1 = 1;
        else
            GPIOA_SFRS->GPAP03.IE1 = 0;
        break;
    case 2:
        if (r)
            GPIOA_SFRS->GPAP03.RE2 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE2 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE2 = 1;
        else
            GPIOA_SFRS->GPAP03.IE2 = 0;
        break;
    case 3:
        if (r)
            GPIOA_SFRS->GPAP03.RE3 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE3 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE3 = 1;
        else
            GPIOA_SFRS->GPAP03.IE3 = 0;
        break;
    case 4:
        if (r)
            GPIOA_SFRS->GPAP4.RE4 = 1;
        if (f)
            GPIOA_SFRS->GPAP4.FE4 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP4.IE4 = 1;
        else
            GPIOA_SFRS->GPAP4.IE4 = 0;
        break;
    default:
        break;
    }
}

uint8_t GPIOA_GetInterruptStatus(uint8_t pos)
{
    uint8_t ret;

    switch (pos) {
    case 0:
        ret = GPIOA_SFRS->GPAP03.ACTDET0;
        break;
    case 1:
        ret = GPIOA_SFRS->GPAP03.ACTDET1;
        break;
    case 2:
        ret = GPIOA_SFRS->GPAP03.ACTDET2;
        break;
    case 3:
        ret = GPIOA_SFRS->GPAP03.ACTDET3;
        break;
    case 4:
        ret = GPIOA_SFRS->GPAP4.ACTDET4;
        break;
    default:
        break;
    }
    return ret;
}

void GPIOA_ClearInterruptStatus(uint8_t pos)
{
    switch (pos) {
    case 0:
        GPIOA_SFRS->GPAP03.CLR0 = 1;
        break;
    case 1:
        GPIOA_SFRS->GPAP03.CLR1 = 1;
        break;
    case 2:
        GPIOA_SFRS->GPAP03.CLR2 = 1;
        break;
    case 3:
        GPIOA_SFRS->GPAP03.CLR3 = 1;
        break;
    case 4:
        GPIOA_SFRS->GPAP4.CLR4 = 1;
        break;
    default:
        break;
    }
}

uint8_t GPIOA_Read(uint8_t pos)
{
    return (uint8_t )(((GPIOA_SFRS->GPADATA[(1 << pos) << 2]) & (1 << pos)) >> pos);
}

void GPIOA_Set(uint8_t pos, uint8_t bit)
{
    GPIOA_SFRS->GPADATA[(1 << pos) << 2] = bit << pos;
}

void GPIOA_EnablePortInput(bool bit, uint8_t mask)
{
}

void GPIOA_EnablePortPullUp(bool bit, uint8_t mask)
{
}

void GPIOA_EnablePortPullDown(bool bit, uint8_t mask)
{
}

void GPIOA_EnablePortOutput(bool bit, uint8_t mask)
{
    if (mask & (1 << 0))
       GPIOA_SFRS->GPAP03.DIR0 = bit;
    if (mask & (1 << 1))
       GPIOA_SFRS->GPAP03.DIR1 = bit;
    if (mask & (1 << 2))
       GPIOA_SFRS->GPAP03.DIR2 = bit;
    if (mask & (1 << 3))
       GPIOA_SFRS->GPAP03.DIR3 = bit;
    if (mask & (1 << 4))
       GPIOA_SFRS->GPAP4.DIR4 = bit;
}

void GPIOA_EnablePortInterrupt(bool r, bool f, uint8_t mask)
{
    if (mask & (1 << 0)) {
        if (r)
            GPIOA_SFRS->GPAP03.RE0 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE0 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE0 = 1;
        else
            GPIOA_SFRS->GPAP03.IE0 = 0;
    }
    if (mask & (1 << 1)) {
        if (r)
            GPIOA_SFRS->GPAP03.RE1 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE1 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE1 = 1;
        else
            GPIOA_SFRS->GPAP03.IE1 = 0;
    }
    if (mask & (1 << 2)) {
        if (r)
            GPIOA_SFRS->GPAP03.RE2 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE2 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE2 = 1;
        else
            GPIOA_SFRS->GPAP03.IE2 = 0;
    }
    if (mask & (1 << 3)) {
        if (r)
            GPIOA_SFRS->GPAP03.RE3 = 1;
        if (f)
            GPIOA_SFRS->GPAP03.FE3 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP03.IE3 = 1;
        else
            GPIOA_SFRS->GPAP03.IE3 = 0;
    }
    if (mask & (1 << 4)) {
        if (r)
            GPIOA_SFRS->GPAP4.RE4 = 1;
        if (f)
            GPIOA_SFRS->GPAP4.FE4 = 1;
        if (r || f)
            GPIOA_SFRS->GPAP4.IE4 = 1;
        else
            GPIOA_SFRS->GPAP4.IE4 = 0;
    }
}

void GPIOA_ClearPortInterruptStatus(uint8_t mask)
{
    uint32_t bitmask = 0;
    if (mask & (1<<0))
        bitmask |= 0x10;
    if (mask & (1<<1))
        bitmask |= (0x10<<8);
    if (mask & (1<<2))
        bitmask |= (0x10<<16);
    if (mask & (1<<3))
        bitmask |= (0x10<<24);
    GPIOA_SFRS->GPAP03.WORD | bitmask;
    bitmask = 0;
    if (mask & (1<<4))
        bitmask |= 0x10;
    GPIOA_SFRS->GPAP4.WORD | bitmask;
}

void GPIOA_PortSet(uint8_t val, uint8_t mask)
{
    GPIOA_SFRS->GPADATA[mask << 2] = val;
}

uint8_t GPIOA_PortRead(uint8_t mask)
{
    return GPIOA_SFRS->GPADATA[mask << 2];
}

void GPIO_ClearInterruptAll(void)
{
    GPIOA_SFRS->GPAP03.WORD |= 0x10101010;
    GPIOA_SFRS->GPAP4.WORD |= 0x10;
}
